<template>
  <div id="gis-view" class="gis-view">
    <div v-if="!fullScreenState" class="gis-tab">
      <common-tabs
        ref="tab"
        v-model="currentTabId"
        :min-hidden-width="120"
        :tabs="tabs"
        :not-empty="true"
        :tabs-after-text="'新建画布'"
        :lock-mode="isLock"
        @action="tabsAction"
      />
    </div>
    <div
      :style="{ height: fullScreenState ? '100%' : 'calc(100% - 38px)' }"
      class="gis-content"
    >
      <div class="container">
        <div
          class="gis-left-panel"
          :style="{
            width: layerPanelState ? 'auto' : 0,
          }"
        >
          <div
            class="gis-panel-container"
            :style="{
              width: layerPanelState ? `${gisSetWidth}px` : 0,
            }"
          >
            <div
              class="left-top layer-management"
              :class="!isLock ? 'lock' : ''"
              :style="{
                height: `${gisLayerManageHeight}px`,
              }"
            >
              <layer-management
                ref="layerManagement"
                :project-id="projectId"
                :current-tab-id="currentTabId"
                :is-lock="isLock"
                @layer-update="layerUpdate"
              />
              <!-- resize  -->
              <div
                id="layer-management-resize-bar"
                class="layer-resize-attribute-tag"
              ></div>
            </div>
            <div
              v-show="!isLock"
              class="left-bottom attribute-tag"
              :style="{
                height: `calc(100% - ${gisLayerManageHeight}px)`,
              }"
            >
              <div
                class="left-bottom-left gis-attribute"
                :style="{
                  width: `${gisAttributeWidth}px`,
                }"
              >
                <layer-attribute />
                <!-- resize  -->
                <div
                  id="attribute-resize-bar"
                  class="attribute-resize-tag"
                ></div>
              </div>
              <div
                class="left-bottom-right gis-tag"
                :style="{
                  width: `calc(100% - ${gisAttributeWidth}px)`,
                }"
              >
                <layer-tags />
              </div>
            </div>
          </div>
          <!-- toggle icon -->
          <a-tooltip placement="top">
            <template slot="title">
              <span>{{
                layerPanelState ? '收起分析工具' : '展开分析工具'
              }}</span>
            </template>
            <div
              v-show="!fullScreenState"
              class="handler"
              @click="toggleGisSettingPanel"
            >
              <a-icon :type="layerPanelState ? 'left' : 'right'" />
            </div>
          </a-tooltip>
          <div
            class="highlight-line"
            :style="{
              left: `${layerPanelState ? gisSetWidth : 0}px`,
            }"
          />
          <!-- 图层-属性-标记 / 图 resize -->
          <div
            v-show="layerPanelState"
            id="map-panel-resize-bar"
            class="map-panel-resize"
          ></div>
        </div>
        <div
          class="gis-right gis-map-analysis"
          :style="{
            width: `calc( 100% - ${layerPanelState ? gisSetWidth : 0}px)`,
          }"
        >
          <gis-analysis
            ref="gisAnalysis"
            :lock-mode="isLock"
            @gis-data-full="gisFullScreen"
            @copy-tab="copyTabId"
          />
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator'
// Watch
// 画布 tab
import CommonTabs from '@/components/common/CommonTabs.vue'
// 数据图层
import LayerManagement from '@/components/gis/LayerManagement.vue'
// 图层属性
import LayerAttribute from '@/components/gis/LayerAttribute.vue'
// 图层标记
import LayerTags from '@/components/gis/LayerTags.vue'
import GisAnalysis from '@/components/gis/GisAnalysis.vue'
import GisStore, { Tab } from '@/store/modules/gis'
import DataViewStore from '@/store/modules/dataview'
import { getLocalStorage, setLocalStorage } from '@/util/util'
import { cloneDeep, debounce } from 'lodash'
import mapUtils from '@/components/gis/map-package/map-utils'

@Component({
  components: {
    CommonTabs,
    LayerManagement,
    LayerAttribute,
    LayerTags,
    GisAnalysis,
  },
  directives: {
    focus: {
      inserted: (element: any) => {
        element.focus()
      },
    },
  },
})
export default class GisView extends Vue {
  // 项目Id (单独从 route 中拿，不引入 DataViewStore)
  public projectId: number = 0
  // 当然 画布 id
  public get currentTabId() {
    return GisStore.currentTabId
  }
  // 所有 画布
  public get tabs(): any[] {
    return GisStore.gisTabs?.map((tab: Tab) => {
      return {
        id: tab.tabId,
        name: tab.tabName,
      }
    })
  }
  private get layerPanelState() {
    return GisStore.layerPanelState
  }

  private get isLock() {
    return DataViewStore.getLock
  }
  public created() {
    // 当前 项目 Id
    this.projectId = Number(this.$route.params.id)
    GisStore.setProjectId(this.projectId)
    this.gisSetWidth = Number(getLocalStorage('gisSetWidth')) || 310
    this.gisLayerManageHeight =
      Number(getLocalStorage('gisLayerManageHeight')) || 400
    this.gisAttributeWidth = Number(getLocalStorage('gisAttributeWidth')) || 110
    this.queryAllTabsByProjectId()
  }

  /**
   * 退出页面时, 销毁gis 相关数据
   */
  public beforeDestroy() {
    GisStore.clearGisInfo()
  }

  public mounted() {
    this.calcPanelFitSize()
    this.initGisPanelEvent()
    this.initLayerManagementEvent()
    this.initAttributeEvent()
    window.addEventListener('resize', this.handleResize)
    this.$once('hook:beforeDestroy', () => {
      window.removeEventListener('resize', this.handleResize)
    })
  }

  private handleResize = debounce(() => this._handleResize(), 200)

  /**
   * 窗口大小改变 适配
   * @private
   */
  private _handleResize() {
    const gisView = document.querySelector('#gis-view') as any
    const { clientHeight } = gisView
    const updateLayerManagementMaxHeight: number = Math.round(
      (clientHeight / 3) * 2
    )
    if (this.gisLayerManageHeight > updateLayerManagementMaxHeight) {
      this.gisLayerManageHeight = updateLayerManagementMaxHeight
    }
    this.layerManagementMaxHeight = updateLayerManagementMaxHeight
    this.layerManagementMinHeight = Math.round(clientHeight / 5)
    setLocalStorage('gisLayerManageHeight', String(this.gisLayerManageHeight))
  }

  @Watch('currentTabId', { immediate: true })
  private handleTabIdChange() {
    this.querySynchronouTabStatus()
  }

  /**
   * 查询是否同步至系统构建
   * 是：禁用 “同步” 按钮
   */
  private querySynchronouTabStatus() {
    GisStore.querySynchronouTabStatus()
  }

  /**
   * 计算页面适配尺寸
   */
  public calcPanelFitSize() {
    const gisView = document.querySelector('#gis-view') as any
    this.panelMaxWidth = gisView.clientWidth > 800 ? 600 : 310
    this.gisLayerManageHeight = Math.round(gisView.clientHeight / 3)
    this.layerManagementMaxHeight = Math.round(gisView.clientHeight / 3) * 2
    this.layerManagementMinHeight = Math.round(gisView.clientHeight / 5)
    setLocalStorage('gisLayerManageHeight', String(this.gisLayerManageHeight))
  }

  private gisSetWidth: number = 310 // panel 三部分总体宽度
  private gisLayerManageHeight: number = 400 // 图层管理高度
  private gisAttributeWidth: number = 110 // 属性宽
  private panelMaxWidth: number = 600 // panel 最大宽度 fix
  private panelMinWidth: number = 310 // panel 最小宽度
  private layerManagementMaxHeight: number = 400 // 图层管理 最大高度
  private layerManagementMinHeight: number = 0 // 图层管理 最小高度
  private get attributeMaxWidth(): number {
    // 属性 最大宽度
    return this.gisSetWidth - 200
  }
  private attributeMinWidth: number = 110 // 属性 最小宽度

  /**
   * 注册 gis panel resize 事件
   */
  public initGisPanelEvent() {
    const resizeBar = document.querySelector('#map-panel-resize-bar') as any

    // 鼠标按下事件
    const mouseDownEvent = ($event: any) => {
      const initCurrentWidth = this.gisSetWidth
      const startX = $event.clientX
      const mouseMoveEvent: any = (event: any) => {
        const endX = event.clientX
        const moveLength = endX - startX
        let newWidth = initCurrentWidth + moveLength
        if (newWidth > this.panelMaxWidth) {
          newWidth = this.panelMaxWidth
        } else if (newWidth < this.panelMinWidth) {
          newWidth = this.panelMinWidth
        }
        this.gisSetWidth = newWidth
        setLocalStorage('gisSetWidth', String(this.gisSetWidth))
        this.adaptAttributeAndTagWidth(newWidth)
        this.$forceUpdate()
      }
      document.addEventListener('mousemove', mouseMoveEvent)
      const mouseUpEvent: any = () => {
        document.removeEventListener('mousemove', mouseMoveEvent)
        document.removeEventListener('mouseup', mouseUpEvent)
        // eslint-disable-next-line @typescript-eslint/no-unused-expressions
        resizeBar.releaseCapture && resizeBar.releaseCapture()
      }
      document.addEventListener('mouseup', mouseUpEvent)
      // eslint-disable-next-line @typescript-eslint/no-unused-expressions
      resizeBar.setCapture && resizeBar.setCapture()
      return false
    }
    resizeBar.addEventListener('mousedown', mouseDownEvent)
    this.$once('hook:beforeDestroy', () => {
      resizeBar.removeEventListener('mousedown', mouseDownEvent)
    })
  }

  /**
   * 修改 panel 整体宽度， 防止标记宽度过小
   * @private
   */
  private adaptAttributeAndTagWidth(panelWidth: number) {
    if (this.gisSetWidth - this.gisAttributeWidth < 200) {
      this.gisAttributeWidth = panelWidth - 200
      setLocalStorage('gisAttributeWidth', String(this.gisAttributeWidth))
    }
  }

  /**
   * 注册 gis panel 图层管理 resize 事件
   */
  public initLayerManagementEvent() {
    const resizeBar = document.querySelector(
      '#layer-management-resize-bar'
    ) as any

    // 鼠标按下事件
    const mouseDownEvent = ($event: any) => {
      const initCurrentHeight = this.gisLayerManageHeight
      const startY = $event.clientY
      const mouseMoveEvent: any = (event: any) => {
        const endY = event.clientY
        const moveLength = endY - startY
        let newHeight = initCurrentHeight + moveLength
        if (newHeight > this.layerManagementMaxHeight) {
          newHeight = this.layerManagementMaxHeight
        } else if (newHeight < this.layerManagementMinHeight) {
          newHeight = this.layerManagementMinHeight
        }
        this.gisLayerManageHeight = newHeight
        setLocalStorage(
          'gisLayerManageHeight',
          String(this.gisLayerManageHeight)
        )
        this.$forceUpdate()
      }
      document.addEventListener('mousemove', mouseMoveEvent)
      const mouseUpEvent: any = () => {
        document.removeEventListener('mousemove', mouseMoveEvent)
        document.removeEventListener('mouseup', mouseUpEvent)
        // eslint-disable-next-line @typescript-eslint/no-unused-expressions
        resizeBar.releaseCapture && resizeBar.releaseCapture()
      }
      document.addEventListener('mouseup', mouseUpEvent)
      // eslint-disable-next-line @typescript-eslint/no-unused-expressions
      resizeBar.setCapture && resizeBar.setCapture()
      return false
    }
    resizeBar.addEventListener('mousedown', mouseDownEvent)
    this.$once('hook:beforeDestroy', () => {
      resizeBar.removeEventListener('mousedown', mouseDownEvent)
    })
  }

  /**
   * 注册 gis panel 属性宽度 resize 事件
   */
  public initAttributeEvent() {
    const resizeBar = document.querySelector('#attribute-resize-bar') as any

    // 鼠标按下事件
    const mouseDownEvent = ($event: any) => {
      const initCurrentWidth = this.gisAttributeWidth
      const startX = $event.clientX
      const mouseMoveEvent: any = (event: any) => {
        const endX = event.clientX
        const moveLength = endX - startX
        let newWidth = initCurrentWidth + moveLength
        if (newWidth > this.attributeMaxWidth) {
          newWidth = this.attributeMaxWidth
        } else if (newWidth < this.attributeMinWidth) {
          newWidth = this.attributeMinWidth
        }
        this.gisAttributeWidth = newWidth
        setLocalStorage('gisAttributeWidth', String(this.gisAttributeWidth))
        this.$forceUpdate()
      }
      document.addEventListener('mousemove', mouseMoveEvent)
      const mouseUpEvent: any = () => {
        document.removeEventListener('mousemove', mouseMoveEvent)
        document.removeEventListener('mouseup', mouseUpEvent)
        // eslint-disable-next-line @typescript-eslint/no-unused-expressions
        resizeBar.releaseCapture && resizeBar.releaseCapture()
      }
      document.addEventListener('mouseup', mouseUpEvent)
      // eslint-disable-next-line @typescript-eslint/no-unused-expressions
      resizeBar.setCapture && resizeBar.setCapture()
      return false
    }
    resizeBar.addEventListener('mousedown', mouseDownEvent)
    this.$once('hook:beforeDestroy', () => {
      resizeBar.removeEventListener('mousedown', mouseDownEvent)
    })
  }

  /**
   * 获取所有画布 tab
   */
  public async queryAllTabsByProjectId() {
    const parameters: any = {
      projectId: this.projectId,
    }
    const tabs: any = await GisStore.queryTabsByProjectId(parameters)
    if (tabs.length === 0) {
      await this.addTab()
    } else {
      let id = tabs[0].tabId
      // localStorage 验证
      const allTabsId: number[] = tabs.map((tab: any) => tab.tabId)
      const localStorageTabId: number = Number(getLocalStorage('currentTabId'))
      if (allTabsId.includes(localStorageTabId)) {
        id = localStorageTabId
      }
      this.changeTabId(id)
    }
  }

  /**
   * 记录上一个 tab 信息
   */
  public recordPreTabInfo() {
    const preTabInfo: any = cloneDeep(
      GisStore.gisTabs.find((tab: Tab) => tab.tabId === GisStore.currentTabId)
    )
    GisStore.setOldTabInfo(preTabInfo)
  }

  /**
   * 复制画布
   */
  public copyTabId(id: number) {
    this.recordPreTabInfo()
    this.changeTabId(id)
  }

  /**
   * 切换 tab
   * @param id
   */
  public changeTabId(id: number) {
    if (GisStore.currentTabId !== id) {
      // 清空图层
      mapUtils.clearMapLayersByLayers(
        GisStore.mapboxInstance,
        GisStore.layerList
      )
      GisStore.setLayerList([])
      GisStore.setLayerData({})
      GisStore.setCurrentTabId(id)
      setLocalStorage('currentTabId', String(id))
    }
  }

  /**
   * GisTabs 组件增删改行为
   * @param actionInfo
   */
  public async tabsAction(actionInfo: any) {
    const { type, parameters } = actionInfo
    switch (type) {
      case 'add-tab': {
        await this.addTab()
        break
      }
      case 'change-tab':
        this.recordPreTabInfo()
        this.changeTabId(parameters.id)
        break
      case 'delete-tab': {
        await this.deleteTab(parameters)
        break
      }
      case 'edit-tab-name':
        await this.editTab(parameters)
        break

      default:
        break
    }
  }

  /**
   * 创建 tab
   */
  public async addTab() {
    const parameters: any = {
      projectId: this.projectId,
    }
    const response: any = await GisStore.addTabByProjectId(parameters)
    if (response.data.code === 100) {
      this.recordPreTabInfo()
      this.changeTabId(response.data.result.tabId)
    }
  }

  /**
   * delete tab
   */
  public async deleteTab(info: any) {
    const { id, activeId } = info
    if (id === GisStore.currentTabId) {
      this.recordPreTabInfo()
    }
    const parameters: any = {
      projectId: this.projectId,
      tabId: id,
    }
    const response: any = await GisStore.deleteGisTab(parameters)
    if (response.data.code === 100) {
      this.changeTabId(activeId)
    }
  }

  /**
   * 修改tabName
   */
  public async editTab(info: any) {
    const { id, newName } = info
    const currentTabs: any = this.tabs.filter((tab: any) => id === tab.id)[0]
    if (newName !== currentTabs.name) {
      GisStore.updateTabName({
        tabId: id,
        tabName: newName,
      })
      const response = await GisStore.gisSaveTabInfoWithLayer()
      if (!response.data.success) {
        this.$message.error('修改标签页名称失败！')
      }
      this.$message.success('修改标签页名称成功！')
    }
  }

  /**
   * toggle 图层管理 属性 标记
   */
  public toggleGisSettingPanel() {
    GisStore.setLayerPanelState(!GisStore.layerPanelState)
  }

  /**
   * 图层更新
   * @param info
   */
  public layerUpdate(info: any) {
    const gisAnalysis: any = this.$refs.gisAnalysis as Vue
    gisAnalysis.layerUpdate(info)
  }

  // 全屏状态
  public get fullScreenState() {
    return GisStore.fullScreenState
  }

  /**
   * 全屏显示
   * 关闭 menu, 图层管理, 属性, 标记, 分析工具
   */
  public gisFullScreen() {
    const state: boolean = !GisStore.fullScreenState
    DataViewStore.setSideMenu(!state)
    GisStore.setFullScreen(state)
    // 全屏
    const gisAnalysis: any = this.$refs.gisAnalysis as Vue
    if (state) {
      GisStore.setRecordPanelAndToolStatus() // 记录页面 panel analysis-tool 打开状态
      GisStore.setLayerPanelState(false)
      GisStore.setGisAnalysisToolState(false)
      this.$nextTick(() => {
        let fullScreenHeight: number = 0
        const gisView: any = document.querySelector('.gis-view')
        if (gisView) {
          fullScreenHeight = gisView?.clientHeight
          gisAnalysis.setDataContainerHeight(fullScreenHeight)
        }
      })
    } else {
      // 退出全屏
      gisAnalysis.setDataContainerHeight(GisStore.gisDataHeight)
    }
  }
}
</script>

<style lang="less" scoped>
@import '@/constants';

.gis-view {
  background: #fff;

  .gis-tab {
    height: 38px;
  }

  .gis-content {
    width: 100%;

    .container {
      display: flex;
      height: 100%;
      width: 100%;

      // 左侧
      .gis-left-panel {
        border-right: 1px solid #e9e9e9;
        box-sizing: border-box;
        height: 100%;
        position: relative;

        .gis-panel-container {
          height: 100%;
          overflow: hidden;
          position: relative;
          // 图层管理
          .layer-management {
            background: #fff;
            box-sizing: border-box;
            position: relative;
            width: 100%;

            &.lock {
              border-bottom: 1px solid #e9e9e9;
            }

            // resize
            .layer-resize-attribute-tag {
              bottom: -5px;
              cursor: ns-resize;
              height: 10px;
              left: 0;
              position: absolute;
              width: 100%;
              z-index: 100;
            }
          }

          // 属性 - 标记
          .attribute-tag {
            display: flex;
            width: 100%;

            // 属性
            .gis-attribute {
              background: #fff;
              border-right: 1px solid #e9e9e9;
              box-sizing: border-box;
              position: relative;

              .attribute-resize-tag {
                cursor: ew-resize;
                height: 100%;
                position: absolute;
                right: -5px;
                top: 0;
                width: 10px;
                z-index: 100;
              }
            }

            // 标记
            .gis-tag {
              background: #fff;
              box-sizing: border-box;
            }
          }
        }

        // 开合

        .handler {
          background: #dee3f7;
          color: #1e49f8;
          cursor: pointer;
          font-size: 9px;
          height: 70px;
          line-height: 70px;
          position: absolute;
          right: -12px;
          text-align: center;
          top: 50%;
          transform: translateY(-100%);
          width: 12px;
          z-index: 101;

          &::before,
          &::after {
            border: 6px solid #dee3f7;
            content: '';
            height: 0;
            left: 0;
            position: absolute;
            width: 0;
          }

          &::before {
            border-right-color: transparent;
            border-top-color: transparent;
            top: -12px;
          }

          &::after {
            border-bottom-color: transparent;
            border-right-color: transparent;
            bottom: -12px;
          }
        }

        .handler:hover {
          background: #6670fa;
          color: #fff;

          &::before {
            border: 6px solid #6670fa;
            border-right-color: transparent;
            border-top-color: transparent;
          }

          &::after {
            border: 6px solid #6670fa;
            border-bottom-color: transparent;
            border-right-color: transparent;
          }
        }

        .highlight-line {
          background: #dee3f7;
          height: 100%;
          position: absolute;
          right: 0;
          top: 0;
          width: 0;
          z-index: 100;
        }

        .handler:hover + .highlight-line {
          background: #6670fa;
          width: 1px;
        }

        // resize
        .map-panel-resize {
          cursor: ew-resize;
          height: 100%;
          position: absolute;
          right: 0;
          top: 0;
          width: 10px;
          z-index: 100;
        }
      }

      // map
      .gis-map-analysis {
        background: #fff;
      }
    }
  }
}
</style>
